library core;

uses sysutils, lists, CoreI, inifiles, {$IFDEF MSWINDOWS}windows {$endif}, log, plugins, events, common, sdl, time;
var ErrInfo:record
str:PChar;
code:cardinal;
end;
ErrorHandlers:PList=nil;
                                                                                         ini:TIniFile;
Core_state : TCore_State=Core_Terminating;
                                                                                         procedure Core_Error(str:PChar; code:cardinal); cdecl;
var PWalk:PList;
begin
                                                      ErrInfo.str := str;
                                                      ErrInfo.code:=code;
PWalk:=ErrorHandlers;
while PWalk<>nil do begin
if TCore_ErrorHandler(PWalk^.data)(ErrInfo.str, ErrInfo.code) then
PWalk:=PWalk^.next else
                                                        break;
end;
                                                                                                            end;
procedure Core_RegisterErrorHandler(handler:TCore_ErrorHandler); cdecl;
                                                                                                            begin
                                             list_InsertBefore(ErrorHandlers, ErrorHandlers, @handler);
                                                                                                            end;
procedure Core_UnregisterErrorHandler(handler:TCore_ErrorHandler); cdecl;
begin
list_remove(ErrorHandlers, @handler);
end;
Function Core_GetState:TCore_State; cdecl;
begin
result:=core_state;
end;
var Core_OldState:TCore_State=Core_Terminating;
Procedure Core_SetState(const state:TCore_State); cdecl;
begin
if Core_State = Core_Terminating then exit;
if (state <= core_running) then begin
Core_OldState:=Core_state;
core_state:=state;
                          end else if state=Core_LastState then core_State:=Core_OldState;
                                              end;
Function CoreInitErrorHandler(var msg:PChar; var code:cardinal):boolean; cdecl;
var s:string;
                                              begin
             s:= 'Error while initializing core: ' + msg;
             log_write(pchar(s), ll_critical);
{$ifdef MSWINDOWS}
MessageBox(0, PChar(s), 'error', mb_iconerror);
{$endif}
halt;
             result:=false;
                                              end;
                                              procedure Core_Init; cdecl;
Procedure WriteDefaultConfig;
                 {$IFDEF MSWINDOWS} var Buf : array[ 0..MAX_PATH ] of Char; {$ENDIF WIN}
TempDir:string;
                 begin
  {$IFDEF LINUX} TempDir:='~/'; {$ELSE MSWINDOWS}
  GetTempPath( MAX_PATH + 1, @Buf[ 0 ] );
TempDir := IncludeTrailingPathDelimiter( PChar( @ Buf[ 0 ] ) );
  {$ENDIF MSWINDOWS}
with ini do begin
WriteString('LOG', 'FileName', TempDir + ChangeFileExt(ExtractFileName(Paramstr(0)), '.log'));
WriteBool('LOG', 'Overwrite', true);
WriteInteger('LOG', 'Level', cardinal(ll_info));
end;
end;
           begin
           Core_RegisterErrorHandler(CoreInitErrorHandler);
           ini:=TIniFile.Create(ChangeFileExt(Paramstr(0), '.ini'));
if not fileexists(ini.FileName) then WriteDefaultConfig;
log_init(ini.ReadString('LOG', 'FileName', ''), ini.ReadBool('LOG', 'Overwrite', true), TLogLevel(ini.ReadInteger('LOG', 'Level', cardinal(ll_info))));
log_write('Initializing core', ll_info);
SDLCheck(SDL_Init(SDL_INIT_TIMER or SDL_Init_Video), 'Core_Init: SDL_init failed');
sdl_wm_setcaption('engine', nil);
sdl_setvideomode(320,200,0,0);
Plugins_Init;
Core_UnregisterErrorHandler(CoreInitErrorHandler);
           end;
        Function CoreMainErrorHandler(var msg:pchar; var code:cardinal):boolean; cdecl;
        begin
result:=false;
log_write(PChar('Error while core_main: ' + msg), ll_critical);
core_close;
        end;
           procedure Core_Main; cdecl;
var MainLoopEvent:PSDL_Event;
           begin
           Core_RegisterErrorHandler(CoreMainErrorHandler);
           log_write('Entering Main Loop', ll_info);
Core_State:=core_running;
CoreTime:=0;
new(MainLoopEvent);
MainLoopEvent^.type_:=Event_MainLoop;
repeat
MainLoopEvent^.user.data1 := pointer(SDL_GetTicks());
SDLCheck(SDL_PushEvent(MainLoopEvent), 'Core_Main');
ProcessEvents;
time_update();
             if Core_State < Core_Running then
sdl_delay(1) else
until core_state = Core_Terminating;
Core_UnregisterErrorHandler(CoreMainErrorHandler);
end;

Procedure Core_Close; cdecl;
begin
log_write('Closing Core', ll_info);
Core_FreePlugins();
Events_free;
ini.Free;
sdl_quit;
end;
exports Core_Error, Core_RegisterErrorHandler, Core_UnregisterErrorHandler, Core_PluginExists, Core_RequirePlugin,
Core_Init, Core_Main, Core_Close, Log_Write(const message:PChar; level:TLogLevel),
Log_Write(const message:PChar; level:TLogLevel; args:array of const) name 'Log_WriteF',
Core_RegisterEventHandler, Core_UnregisterEventHandler, Core_GetState, Core_SetState, Core_GetTime, Core_AddTimer,
Core_RemoveTimer, Core_ScanForPlugins, Core_FreePlugins;
                                                                                                            begin
                                                                                                                                                                                                                            end.
